home *** CD-ROM | disk | FTP | other *** search
/ Power Programmierung / Power-Programmierung (Tewi)(1994).iso / magazine / msysjour / vol06 / 03 / winedd / driver.c < prev    next >
Text File  |  1991-05-01  |  12KB  |  382 lines

  1. /* ----------------------------- DRIVER.C ----------------------------------
  2.                      Embedded Device Driver Application.
  3.                             Device Driver module.
  4.  
  5.                            Spark Software Inc. 1991.
  6.  
  7.     INTHANDLER          -   The interrupt service routine.
  8.     DevOpen             -   Opens the pseudodevice.
  9.     DevClose            -   Closes the pseudodevice.
  10.     DevRead             -   Reads the pseudodevice.
  11.     GetNumUnreadItems   -   Returns the number of register sets not yet read.
  12.     GetDevError         -   Returns and resets device status information.
  13.    ------------------------------------------------------------------------- */
  14.  
  15. /* The following is an intentionally empty definition; this is used to tell */
  16. /* the compiler that we wish to have global variables declared in this      */
  17. /* source module and only defined in all others.                            */
  18. #define PUBLIC
  19.  
  20. #include <windows.h>
  21. #include <dos.h>
  22. #include "devdefs.h"
  23. #include "intnum.h"
  24. #include "dprivate.h"
  25. #include "device.h"
  26.  
  27. /* Public function prototypes. */
  28. PUBLIC VOID FAR PASCAL WEP( int );  /* Called by the kernel on DLL exit. */
  29.  
  30. /* Private data object declarations. */
  31. PRIVATE VOID (interrupt FAR *lpOldHandler)( );/* Address of the old handler. */
  32. PRIVATE BOOL bWrapped;          /* Have we wrapped around the buffer?        */
  33. PRIVATE WORD wNumDevErrors;     /* Number of errors while processing ints.   */
  34. PRIVATE WORD wDevError;         /* Type of errors while processing ints.     */
  35. PRIVATE int  nUnreadItems;      /* Number of register sets not yet read.     */
  36. PRIVATE HWND hWndDevUser;       /* Handle of window that opened the device.  */
  37. PRIVATE REGISTERS  InterruptData[ MAX_INTERRUPTS ]; /* Saved registers.      */
  38. PRIVATE PREGISTERS pIntRegisterSet;     /* Modified by INTHANDLER( ).        */
  39. PRIVATE PREGISTERS pReadRegisterSet;    /* Modified by DevRead( ).           */
  40. PRIVATE union  REGS  Regs;              /* For setting up interrupt vector.  */
  41. PRIVATE struct SREGS SRegs;             /* "                                 */
  42.  
  43.  
  44. PUBLIC VOID FAR INTERRUPT_ATTRIBUTE INTHANDLER( _es , _ds , _di , _si , _bp , _sp , _bx , _dx , _cx , _ax , _ip , _cs , _flags )
  45. unsigned _es;
  46. unsigned _ds;
  47. unsigned _di;
  48. unsigned _si;
  49. unsigned _bp;
  50. unsigned _sp;
  51. unsigned _bx;
  52. unsigned _dx;
  53. unsigned _cx;
  54. unsigned _ax;
  55. unsigned _ip;
  56. unsigned _cs;
  57. unsigned _flags;
  58. {
  59.     BOOL       bLocalWrapped;
  60.     PREGISTERS pLocalIntRegisterSet;
  61.     PREGISTERS pLocalReadRegisterSet;
  62.  
  63.  
  64.     /* Copy data segment information into the stack. */
  65.     pLocalIntRegisterSet = pIntRegisterSet;
  66.     pLocalReadRegisterSet = pReadRegisterSet;
  67.     bLocalWrapped = bWrapped;
  68.  
  69.     /* Prepare for next time IMMEDIATELY to avoid reentrancy problems. */
  70.     nUnreadItems++;
  71.  
  72.     /* Need to wrap? */
  73.     if( ++pIntRegisterSet >= InterruptData + MAX_INTERRUPTS )
  74.     {
  75.         /* Wrap around to the beginning of the buffer for next time. */
  76.         bWrapped = TRUE;
  77.         pIntRegisterSet = InterruptData;
  78.     }
  79.  
  80.     /* For now, we're using stack variables; it's OK to turn interrupts on. */
  81.     _enable( );
  82.  
  83.     /* Buffer the interrupt data. */
  84.     /* NOTE: we're doing it the boring way, as opposed to arranging the      */
  85.     /* elements of REGISTERS to be the same as the argument list, then doing */
  86.     /* the assignment *pLocalIntRegisterSet = *(PREGISTERS)&es.  That can    */
  87.     /* be done, but it is both arcane and possibly dependent on the compiler */
  88.     /* version: should the arglist change in future versions of the compiler,*/
  89.     /* that code might break.                                                */
  90.     pLocalIntRegisterSet->ax    = _ax;
  91.     pLocalIntRegisterSet->bx    = _bx;
  92.     pLocalIntRegisterSet->cx    = _cx;
  93.     pLocalIntRegisterSet->dx    = _dx;
  94.     pLocalIntRegisterSet->cs    = _cs;
  95.     pLocalIntRegisterSet->ds    = _ds;
  96.     pLocalIntRegisterSet->es    = _es;
  97.     pLocalIntRegisterSet->si    = _si;
  98.     pLocalIntRegisterSet->di    = _di;
  99.     pLocalIntRegisterSet->bp    = _bp;
  100.     pLocalIntRegisterSet->sp    = _sp;
  101.     pLocalIntRegisterSet->ip    = _ip;
  102.     pLocalIntRegisterSet->flags = _flags;
  103.  
  104.     /* Check for buffer overrun, (new data overwriting old unread data). */
  105.     if( bLocalWrapped && pLocalIntRegisterSet > pLocalReadRegisterSet )
  106.     {
  107.         /* Changing data segment vars. */
  108.         _disable( );
  109.  
  110.         /* Log the error. */
  111.         wDevError |= DEVERROR_OVERRUN;
  112.         wNumDevErrors++;
  113.  
  114.         /* Only using stack variables. */
  115.         _enable( );
  116.     }
  117.  
  118.     /* NOTE: interrupts MUST be left on when exiting an ISR. */
  119.  
  120. }/* INTHANDLER( ) */
  121.  
  122.  
  123. PUBLIC BOOL FAR PASCAL DevOpen( hWnd )
  124. HWND hWnd;
  125. {
  126.     /* Is the device in use? */
  127.     if( hWndDevUser )
  128.     {
  129.         /* Device already in use. */
  130.         wDevError |= DEVERROR_NOTOWNER;
  131.         wNumDevErrors++;
  132.         return FALSE;
  133.     }
  134.  
  135.     /* If the device is a hardware device, we should check for its       */
  136.     /* existence, possibly using inp( ), inpw( ), outp( ) or outpw( )    */
  137.     /* to check an I/O port for an expected value.  This code goes here. */
  138.  
  139.     /* Set up our buffering. */
  140.     pIntRegisterSet = pReadRegisterSet = InterruptData;
  141.  
  142.     /* Save the handle of the calling window. */
  143.     hWndDevUser = hWnd;
  144.  
  145.     /* Say that we have no device errors. */
  146.     wNumDevErrors = wDevError = 0;
  147.  
  148.     /* Tell any readers that we're not wrapped yet. */
  149.     bWrapped = FALSE;
  150.  
  151.     /* Get the old ISR's address. */
  152.     Regs.h.ah = DOSSVC_GETVECT;
  153.     Regs.h.al = INTNUM;
  154.     intdosx( &Regs , &Regs , &SRegs );
  155.     FP_SEG( lpOldHandler ) = SRegs.es;
  156.     FP_OFF( lpOldHandler ) = Regs.x.bx;
  157.  
  158.     /* Install the new interrupt handler. */
  159.     Regs.h.ah = DOSSVC_SETVECT;
  160.     Regs.h.al = INTNUM;
  161.     SRegs.ds  = HIWORD( (DWORD)INTHANDLER );
  162.     Regs.x.dx = LOWORD( (DWORD)INTHANDLER );
  163.     intdosx( &Regs , &Regs , &SRegs );
  164.     return TRUE;
  165.  
  166. }/* DevOpen( ) */
  167.  
  168.  
  169. PUBLIC BOOL FAR PASCAL DevClose( hWnd )
  170. HWND hWnd;
  171. {
  172.     /* Is this the device user? */
  173.     if( hWnd != hWndDevUser )
  174.     {
  175.         /* This user does not own the device.  Call the device police. */
  176.         wDevError |= DEVERROR_NOTOWNER;
  177.         wNumDevErrors++;
  178.         return FALSE;
  179.     }
  180.  
  181.     /* If the device is a hardware device, the port commands */
  182.     /* necessary to shut down the device go here.            */
  183.  
  184.     /* Uninstall the interrupt handler. */
  185.     Regs.h.ah = DOSSVC_SETVECT;
  186.     Regs.h.al = INTNUM;
  187.     SRegs.ds  = HIWORD( (DWORD)lpOldHandler );
  188.     Regs.x.dx = LOWORD( (DWORD)lpOldHandler );
  189.     intdosx( &Regs , &Regs , &SRegs );
  190.  
  191.     /* Say that hWnd is no longer using this device. */
  192.     hWndDevUser = (HWND)NULL;
  193.     return TRUE;
  194.  
  195. }/* DevClose( ) */
  196.  
  197.  
  198. PUBLIC WORD FAR PASCAL DevRead( hWnd , lpRegisters , wItemsRequested )
  199. HWND                 hWnd;
  200. register LPREGISTERS lpRegisters;
  201. register WORD        wItemsRequested;
  202. {
  203.     BOOL          bBreak;
  204.     register WORD wItemsRead;
  205.  
  206.  
  207.     /* Is this the device user? */
  208.     if( hWnd != hWndDevUser )
  209.     {
  210.         /* No. */
  211.         wDevError |= DEVERROR_NOTOWNER;
  212.         wNumDevErrors++;
  213.         return 0;
  214.     }
  215.  
  216.     /* Check for new data. */
  217.     wItemsRead = 0;
  218.     bBreak = FALSE;
  219.     _disable( );
  220.     if( pReadRegisterSet == pIntRegisterSet && !bWrapped )
  221.     {
  222.         /* No new data. */
  223.         bBreak = TRUE;
  224.     }
  225.     _enable( );
  226.  
  227.     /* Copy each item requested to the user's buffer; */
  228.     /* check for previous errors on each iteration.   */
  229.     /* NOTE: this code is written in such a way that interrupts are allowed */
  230.     /* to sneak in during the JMP instruction that gets us back to the top  */
  231.     /* of the loop and the instructions used to evaluate the while( )       */
  232.     /* condition.  This allows us to protect the integrity of vars. in the  */
  233.     /* data segment AND allow interrupts to be speedily processed.  In this */
  234.     /* section of the code, it doesn't pay to use stack variables (almost   */
  235.     /* every line must reference a data segment variable).                  */
  236.     while( !bBreak && !wNumDevErrors && wItemsRequested )
  237.     {
  238.         /* Turn interrupts off for this iteration. */
  239.         _disable( );
  240.  
  241.         /* Copy this register set. */
  242.         *lpRegisters = *pReadRegisterSet;
  243.  
  244.         /* Prepare for next time. */
  245.         lpRegisters++ , pReadRegisterSet++ , wItemsRead++ , wItemsRequested-- , nUnreadItems--;
  246.  
  247.         /* Need to wrap? */
  248.         if( pReadRegisterSet >= InterruptData + MAX_INTERRUPTS )
  249.         {
  250.             if( bWrapped )
  251.             {
  252.                 /* Wrap around to the beginning of the buffer. */
  253.                 bWrapped = FALSE;
  254.                 pReadRegisterSet = InterruptData;
  255.             }
  256.             else
  257.             {
  258.                 /* We've somehow read past the last saved register set.  */
  259.                 /* This is an internal inconsistency - log it and leave. */
  260.                 wDevError |= DEVERROR_INTERNAL;
  261.                 wNumDevErrors++;
  262.             }
  263.         }
  264.  
  265.         /* Should we terminate the loop? */
  266.         if( pReadRegisterSet == pIntRegisterSet )
  267.         {
  268.             /* Break at the end of this iteration. */
  269.             bBreak = TRUE;
  270.         }
  271.  
  272.         /* Turn interrupts back on. */
  273.         _enable( );
  274.     }
  275.  
  276.     return wItemsRead;
  277.  
  278. }/* DevRead( ) */
  279.  
  280.  
  281. PUBLIC int FAR PASCAL GetNumUnreadItems( hWnd )
  282. HWND hWnd;
  283. {
  284.     /* Is this the device user? */
  285.     if( hWnd != hWndDevUser )
  286.     {
  287.         /* No. */
  288.         /* Turn interrupts off for now. */
  289.         _disable( );
  290.  
  291.         /* Record the error. */
  292.         wDevError |= DEVERROR_NOTOWNER;
  293.         wNumDevErrors++;
  294.  
  295.         /* Turn interrupts back on. */
  296.         _enable( );
  297.         return -1;
  298.     }
  299.  
  300.     /* Return the number of register sets not yet read. */
  301.     return nUnreadItems;
  302.  
  303. }/* GetNumUnreadItems( ) */
  304.  
  305.  
  306. PUBLIC WORD FAR PASCAL GetDevError( hWnd , lpwDevError , bReset )
  307. HWND   hWnd;
  308. LPWORD lpwDevError;
  309. BOOL   bReset;
  310. {
  311.     WORD wNumDevErrorsCopy;
  312.  
  313.  
  314.     /* Is this the device user? */
  315.     if( hWnd != hWndDevUser )
  316.     {
  317.         /* No. */
  318.         if( lpwDevError )
  319.         {
  320.             /* Turn interrupts off for now. */
  321.             _disable( );
  322.  
  323.             *lpwDevError = wDevError |= DEVERROR_NOTOWNER;
  324.  
  325.             /* Turn interrupts back on. */
  326.             _enable( );
  327.         }
  328.         return ++wNumDevErrors;
  329.     }
  330.  
  331.     /* Turn interrupts off for now. */
  332.     _disable( );
  333.  
  334.     /* Copy the bitflags and number of device errors. */
  335.     if( lpwDevError )
  336.     {
  337.         *lpwDevError = wDevError;
  338.     }
  339.  
  340.     wNumDevErrorsCopy = wNumDevErrors;
  341.  
  342.     if( bReset )
  343.     {
  344.         wNumDevErrors = wDevError = 0;
  345.     }
  346.  
  347.     /* Turn interrupts back on. */
  348.     _enable( );
  349.  
  350.     return wNumDevErrorsCopy;
  351.  
  352. }/* GetDevError( ) */
  353.  
  354.  
  355. PUBLIC VOID FAR PASCAL WEP( nExitType )
  356. int nExitType;
  357. {
  358.     /* If the device is a hardware device, the port commands */
  359.     /* necessary to shut down the device go here.            */
  360.  
  361.     switch( nExitType )
  362.     {
  363.     case WEP_SYSTEM_EXIT:
  364.         /* System shutdown in progress.  Respond accordingly. */
  365.         return;
  366.  
  367.     case WEP_FREE_DLL:
  368.         /* DLL use count is zero.  Respond accordingly. */
  369.         return;
  370.  
  371.     default:
  372.         /* Undefined value.  Ignore it. */
  373.         /* NOTE: even if the kernel hasn't passed us a recognized */
  374.         /* nExitType, we should still have shut down the hardware */
  375.         /* device before entering this switch.                    */
  376.         return;
  377.     }
  378.  
  379. }/* WEP( ) */
  380.  
  381. /* EOF */
  382.